package com.hz.cheetah.client;

import com.hz.cheetah.common.bean.RpcRequest;
import com.hz.cheetah.common.bean.RpcResponse;
import com.hz.cheetah.common.util.StringUtil;
import com.hz.cheetah.hub.ServiceDiscovery;
import com.hz.cheetah.hub.protocol.CheetahURL;
import javassist.ClassPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;

/**
 * RPC 代理帮助类（用于执行 RPC 服务）
 *
 * @author yangchuan
 * @since 1.0.0
 */

public class CheetahProxyHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(CheetahProxyHelper.class);


    private ServiceDiscovery serviceDiscovery;
    ClassPool pool = new ClassPool(true);//ClassPool.getDefault();


    public CheetahProxyHelper(ServiceDiscovery serviceDiscovery) {
        this.serviceDiscovery = serviceDiscovery;
    }


    public Object invoke(String serviceName,String serviceVersion,
                         String methodName,
                         Class<?>[] argsTypes, Object[] args) throws Throwable {
        // 创建 RPC 请求对象并设置请求属性
        RpcRequest request = new RpcRequest();
        request.setRequestId(UUID.randomUUID().toString());
        request.setInterfaceName(serviceName);
        request.setServiceVersion(serviceVersion);
        request.setMethodName(methodName);
        request.setParameterTypes(argsTypes);
        request.setParameters(args);
        if (StringUtil.isNotEmpty(serviceVersion)) {
            serviceName += "-" + serviceVersion;
        }
        long time = System.currentTimeMillis();
        RpcResponse response = execute(request,serviceName,null,0,null);
        LOGGER.debug("time: {}ms", System.currentTimeMillis() - time);
        if (response == null) {
            throw new RuntimeException("response is null");
        }
        // 返回 RPC 响应结果
        if (response.hasException()) {
            throw response.getException();
        } else {
            return response.getResult();
        }
    }

    private RpcResponse execute(RpcRequest request,String serviceName,CheetahURL old, int num,Exception e){
        if(num < 3){
            CheetahURL serviceAddress = getServiceAddress(serviceName,old);
            CheetahClient client = new CheetahClient(serviceAddress);
            try {
                RpcResponse response = client.send(request);
                if(response == null){
                    num += 1;
                    LOGGER.warn("retry num:{}",num);
                    return execute(request,serviceName,serviceAddress,num,null);
                }
                return response;
            }catch (Exception e1){
                num += 1;
                LOGGER.warn("retry num:{}",num);
                return execute(request,serviceName,serviceAddress,num,e1);
            }
        }else{
            RpcResponse response = new RpcResponse();
            response.setRequestId(request.getRequestId());
            response.setException(e);
            return response;
        }
    }

    protected CheetahURL getServiceAddress(String serviceName,CheetahURL old) {
        CheetahURL serviceAddress = null;
        if (serviceDiscovery != null) {
            if(old == null){
                serviceAddress = serviceDiscovery.discover(serviceName);
            }else{
                serviceAddress = serviceDiscovery.reDiscover(serviceName,old);
            }

            LOGGER.debug("discover service: {} => {}", serviceName, serviceAddress);
        }
        if (serviceAddress == null) {
            throw new RuntimeException("server address is empty");
        }
        return serviceAddress;

    }
}
